package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstants;
import com.zzyl.constant.Constants;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DevicePropertyStatusVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.sql.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description DeviceServiceImpl
 * @Author wangwei
 * @Date 2024-09-10
 */
@Service
@Slf4j
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private Client client;
    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    /**
     * 从物联网中同步数据
     */
    @Override
    public void syncProductList() {
        //获取产品信息列表
        List<ProductVo> allProduct = getAllProduct();
        //将数据存入redis缓存
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(allProduct));
    }

    /**
     * 查询所有的产品信息
     * @return
     */
    @Override
    public List<ProductVo> allProduct() {
        String products = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        List<ProductVo> productVos = JSONUtil.toList(products, ProductVo.class);
       /* List<ProductVo> allProduct = getAllProduct();*/
        return productVos;
    }

    /**
     * 注册设备信息
     *
     * @param deviceDto
     */
    @Override
    public void registerDevice(DeviceDto deviceDto) {
        //0.判断该设备是否存在
        Integer count = deviceMapper.selectDeviceCount(deviceDto.getDeviceName());
        if (count.intValue()>0){
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        //1.信息补全
        //1.1获取产品名称
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        QueryProductResponse queryProductResponse;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取产品详情 信息失败,{}",e.getMessage());
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        deviceDto.setProductName(queryProductResponse.getBody().getData().getProductName());
        //1.2设置物理位置类型(-1:老人.0:楼层,1:房间,2:床位)
        if (deviceDto.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())){
            deviceDto.setPhysicalLocationType(-1);
        }
        //2.注册设备
        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        //2.1补全需要的信息
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        registerDeviceRequest.setProductKey(queryProductRequest.getProductKey());
        //2.2注册回显设备id
        RegisterDeviceResponse registerDeviceResponse;
        try {
            registerDeviceResponse = client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("注册 设备失败,{}",e.getMessage());
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        deviceDto.setIotId(registerDeviceResponse.getBody().getData().getIotId());
        //3.插入数据库
        try {
            deviceMapper.insertSelective(BeanUtil.toBean(deviceDto, Device.class));
        } catch (Exception e) {
            //4.如果失败,删除注册的设备信息
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotId(aliIoTConfigProperties.getIotInstanceId());
            deleteDeviceRequest.setIotId(registerDeviceResponse.getBody().getData().getIotId());
            DeleteDeviceResponse deleteDeviceResponse;
            try {
                deleteDeviceResponse = client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                e.printStackTrace();
                log.error("删除注册的设备信息失败,{}",e.getMessage());
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }
            e.printStackTrace();
            log.error("插入数据库信息失败,{}",e.getMessage());
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
    }

    /**
     * 查询所有的产品信息
     * @return
     */
    private List<ProductVo> getAllProduct() {
        QueryProductListRequest queryProductListRequest = new QueryProductListRequest();
        queryProductListRequest.setCurrentPage(1);
        queryProductListRequest.setPageSize(200);
        QueryProductListResponse queryProductListResponse = null;
        queryProductListRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        try {
            queryProductListResponse = client.queryProductList(queryProductListRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        /*List<ProductVo> productVos = queryProductListResponse.getBody().getData().getList().getProductInfo().stream()
                .map(product -> BeanUtil.toBean(product, ProductVo.class))
                .collect(Collectors.toList());*/
        if (!queryProductListResponse.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        List<ProductVo> productVos = BeanUtil.copyToList(queryProductListResponse.getBody().getData().getList().getProductInfo(), ProductVo.class);
        log.info("获取的产品列表信息为:{}",productVos );
        return productVos;
    }

    /**
     * 分页查询
     * @param devicePageQueryDto
     */
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {

        PageHelper.startPage(devicePageQueryDto.getPageNum(),devicePageQueryDto.getPageSize());
        Page<DeviceVo> deviceVos = deviceMapper.selectByPage(devicePageQueryDto);
        return PageResponse.of(deviceVos, DeviceVo.class);
    }

    /**
     * 获取设备的详细信息
     *
     * @param request
     * @return
     */
    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest request) {
        //1.从IOT的设备中获取部分信息
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        log.info("request的请求信息为,{}",request);
        QueryDeviceDetailResponse queryDeviceDetailResponse;
        try {
            queryDeviceDetailResponse = client.queryDeviceDetail(request);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取设备详细信息失败,{}",e.getMessage());
            throw new RuntimeException("获取设备详细信息失败");
        }
        //2.从数据库获取部分信息
        Device device = deviceMapper.getDeviceDetailInfo(request.getIotId());
        DeviceVo deviceVo = BeanUtil.toBean(device, DeviceVo.class);
        //3.封装DeviceVo
        BeanUtil.copyProperties(queryDeviceDetailResponse.getBody().getData(),deviceVo,
                true);
        log.info("封装后的返回值对象,{}",deviceVo);
        return deviceVo;
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param deviceDto
     * @return
     */
    @Override
    public Object getDevicePropertyStatus(DeviceDto deviceDto) {
        //1.数据类型转换为QueryDevicePropertyStatusRequst
        QueryDevicePropertyStatusRequest propertyStatusRequest = BeanUtil.toBean(deviceDto, QueryDevicePropertyStatusRequest.class);
        //2.补全数据
        propertyStatusRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        log.info("补全的信息为,{}",propertyStatusRequest);
        //3.查询信息
        QueryDevicePropertyStatusResponse propertyStatusResponse;
        try {
            propertyStatusResponse = client.queryDevicePropertyStatus(propertyStatusRequest);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询指定设备的物模型运行状态,{}",e.getMessage());
            throw new RuntimeException("查询指定设备的物模型运行状态失败");
        }
        //4.封装数据返回

        return propertyStatusResponse.getBody().getData();
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param deviceDto
     * @return
     */
    @Override
    public Object queryThingModelPublishedInfo(DeviceDto deviceDto) {
        //1.补全数据
        QueryThingModelPublishedRequest queryThingModelPublishedRequest = new QueryThingModelPublishedRequest();
        queryThingModelPublishedRequest.setProductKey(deviceDto.getProductKey());
        queryThingModelPublishedRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryThingModelPublishedRequest.setResourceGroupId(aliIoTConfigProperties.getConsumerGroupId());
        //2.查询信息
        QueryThingModelPublishedResponse queryThingModelPublishedResponse;
        try {
            queryThingModelPublishedResponse = client.queryThingModelPublished(queryThingModelPublishedRequest);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查看指定产品的已发布物模型中的功能定义详情失败,{}",e.getMessage());
            throw new RuntimeException("查看指定产品的已发布物模型中的功能定义详情失败");
        }
        if (!queryThingModelPublishedResponse.getBody().getSuccess()){
            throw new RuntimeException("查看指定产品的已发布物模型中的功能定义详情失败");
        }
        //3.封装返回
        return queryThingModelPublishedResponse.getBody().getData();
    }

    /**
     * 修改设备备注名称
     *
     * @param deviceDto
     */
    @Override
    public void UpdateDeviceInfo(DeviceDto deviceDto) {
        //1.数据类型转换
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        //2.判断设备类型是否为0
        if (device.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())){
            device.setPhysicalLocationType(-1);
        }
        //3.更新iot
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo info = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        info.setIotId(device.getIotId());
        info.setNickname(device.getNickname());
        ArrayList<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> infos = new ArrayList<>();
        infos.add(info);
        request.setDeviceNicknameInfo(infos);
        BatchUpdateDeviceNicknameResponse batched;
        try {
            batched = client.batchUpdateDeviceNickname(request);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("修改设备备注名称失败,{}",e.getMessage());
            throw new RuntimeException("修改设备备注名称失败");
        }
        if (!batched.getBody().getSuccess()){
            throw new RuntimeException("修改设备备注名称失败");
        }
        //4.更新数据库
        deviceMapper.updateByPrimaryKeySelective(device);
    }

    /**
     * 删除设备信息
     *
     * @param deviceDto
     */
    @Override
    public void deleteDevice(DeviceDto deviceDto) {
        //1.在iot中删除设备
        DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
        deleteDeviceRequest.setIotId(deviceDto.getIotId());
        deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        DeleteDeviceResponse deleteDeviceResponse;
        try {
            deleteDeviceResponse = client.deleteDevice(deleteDeviceRequest);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("删除设备失败,{}",e.getMessage());
            throw new RuntimeException("删除设备失败");
        }
        //2.在数据库中 删除
        deviceMapper.deleteByIotId(deviceDto.getIotId());
    }
}
